const { Service } = require('egg');
const { v4: uuidV4 } = require('uuid');
const moment = require('moment');
const order_table = 'order_info',
  order_process_table = 'order_process',
  product_table = 'product',
  user_table = 'user',
  order_product_table = 'order_product';
const inventory_table = 'inventory';
class OrderService extends Service {

  async list(name, describe, status, order = 'create_time', method = 'desc', pageIndex, pageSize) {
    const ctx = this.ctx;
    try {
      const sql = ctx.app.knex().select('t1.name', 't1.uuid', 't1.describe',
        't1.type', 't1.status', 't1.create_time', 't1.update_time', 't1.create_by', 't1.update_by',
        't1.is_delete', 't1.create_time', 't1.update_time', 't1.create_by',
        't1.update_by', 't3.name as create_name', 't4.name as update_name'
      )
        .from(`${order_table} as t1`)
        .leftJoin(`${user_table} as t3`, function() {
          this.on('t3.uuid', '=', 't1.create_by');
        })
        .leftJoin(`${user_table} as t4`, function() {
          this.on('t4.uuid', '=', 't1.update_by');
        })
        .where('t1.is_delete', 0);

      const countSql = ctx.app.knex().count('t1.uuid as count')
        .from(`${order_table} as t1`)
        .where('t1.is_delete', 0);

      if (name) {
        sql.andWhereLike('t1.name', `%${name}%`);
        countSql.andWhereLike('t1.name', `%${name}%`);
      }

      if (describe) {
        sql.andWhereLike('t1.describe', `%${describe}%`);
        countSql.andWhereLike('t1.describe', `%${describe}%`);
      }

      if (status) {
        sql.andWhere('t1.status', status);
        countSql.andWhere('t1.status', status);
      }

      const list = await sql.orderBy(order, method).limit(Number(pageSize)).offset(Number(pageSize) * (Number(pageIndex) - 1));
      const count = await countSql;


      const result = {
        list,
        count: count[0].count,
      };

      return result;
    } catch (error) {
      throw error;
    }
  }


  async insert(name, describe, address_id, type, level, status, product) {
    const ctx = this.ctx;
    const trx = await ctx.app.knex.transaction();
    try {
      const { id: user_id } = ctx.session;
      const time = moment();
      const instance = {
        uuid: uuidV4(),
        name, describe, address_id, type, level, status,
        create_time: moment(time).format('YYYY-MM-DD HH:mm:ss'),
        update_time: moment(time).format('YYYY-MM-DD HH:mm:ss'),
        update_by: user_id,
        create_by: user_id,
      };

      await this.checkInventory(product, ctx);

      const inventory_instances = await ctx.service.product.orderInventory(product);

      const order_product_instances = await ctx.service.product.insertInstance(instance.uuid, product);

      const order_process_instance = await ctx.service.process.insert(instance.uuid, 0, 1, '等待确定订单');

      await trx(order_table).insert(instance);
      await trx(inventory_table).insert(inventory_instances);
      await trx(order_product_table).insert(order_product_instances);
      await trx(order_process_table).insert(order_process_instance);

      await trx.commit();
      return instance;
    } catch (error) {
      await trx.rollback();
      throw error;
    }
  }

  async cancel(order_id, remark) {
    const ctx = this.ctx;
    const trx = await ctx.app.knex.transaction();
    try {
      const { id: user_id } = ctx.session;
      const time = moment();
      const instance = {
        is_delete: 0,
        update_by: user_id,
        update_time: moment(time).format('YYYY-MM-DD'),
      };

      // step.1 更新订单;   step.2 释放订单获取的资源
      const data = await ctx.app.knex(order_product_table).select('product_id, number').where({ order_id });
      await trx(order_table).update(instance).where({ order_id });

      for (const d of data) {
        const update_instance = await ctx.app.knex(product_table).select('*').where({ uuid: d.product_id, type: 3 });
        update_instance.number -= d.number;

        await trx(product_table).update(update_instance).where({ uuid: update_instance.uuid });
      }

      const next_process = await ctx.service.process.trxCancel(order_id, remark, trx);


      console.log(` >>>>>>>>>>>> ${JSON.stringify(next_process)}`);
      await trx.commit();
      return instance;
    } catch (error) {
      await trx.rollback();
      throw error;
    }
  }

  async finish(order_id, remark) {
    const ctx = this.ctx;
    const trx = await ctx.app.knex.transaction();
    try {
      const { id: user_id } = ctx.session;
      const time = moment();

      const instance = await ctx.app.knex(order_table).select('*').where({ uuid: order_id })
        .first();

      if (!instance) {
        throw new Error('当前订单不存在');
      }


      instance.status = 2;
      instance.update_by = user_id;
      instance.update_time = moment(time).format('YYYY-MM-DD HH:mm:ss');
      await ctx.service.process.trxFinish(order_id, remark, trx);
      await trx(order_table).update(instance).where({ uuid: order_id });
      await trx.commit();
      return instance;
    } catch (error) {
      await trx.rollback();
      throw error;
    }
  }

  async change(address_id, order_id) {

    const ctx = this.ctx;
    const trx = await ctx.app.knex.transaction();
    try {
      const { id: user_id } = this.ctx;
      const time = moment();

      const instance = await ctx.app.knex(order_table).select('*').where({ uuid: order_id })
        .first();

      if (!instance) {
        throw new Error('当前订单不存在');
      }

      if (moment(instance.create_time).add(2, 'h').isBefore(moment(time).format('YYYY-MM-DD HH:mm:ss'))) {
        throw new Error('当前时间已超过下单两个小时, 无发修改地址');
      }

      instance.update_time = moment(time).format('YYYY-MM-DD HH:mm:ss');
      instance.update_by = user_id;
      instance.address_id = address_id;


      await trx(order_table).update(instance).where({ uuid: order_id });

      return instance;
    } catch (error) {
      throw error;
    }
  }

  async refuse(order_id, remark) {
    const ctx = this.ctx;
    const trx = await ctx.app.knex.transaction();

    try {
      const { id: user_id } = ctx.session;
      const time = moment();

      const instance = await ctx.app.knex(order_table).select('*').where({ uuid: order_id })
        .first();

      if (!instance) {
        throw new Error('订单不存在');
      }

      instance.status = 2;
      instance.update_by = user_id;
      instance.update_time = moment(time).format('YYYY-MM-DD HH:mm:ss');


      await ctx.service.process.trxRefuse(order_id, remark, trx);

      await trx(order_table).update(instance).where({ uuid: order_id });

      // 消息发送 --- 对应消息队列

      await trx.commit();
      return instance;
    } catch (error) {
      await trx.rollback();
      throw error;
    }
  }

  async delete(order_ids) {
    const ctx = this.ctx;
    const trx = await ctx.app.knex.transaction();
    try {
      const { id: user_id } = ctx.session;
      const time = moment();

      const instance = {};
      instance.update_time = moment(time).format('YYYY-MM-DD HH:mm:ss');
      instance.update_by = user_id;
      instance.is_delete = 1;

      await trx(order_table).update(instance).whereIn('uuid', order_ids);

      return instance;
    } catch (error) {
      throw error;
    }
  }

  async checkInventory(products, ctx) {
    try {
      let product_ids = '';
      for (const product of products) {
        // product_ids = product_ids + product.product_id + ',';
        product_ids = `'${product_ids}${product.product_id}', `;
      }

      product_ids = product_ids.substring(0, product_ids.length - 2);

      const sql = `
      select m.i - m.o - m.p as number, m.product_id,n.name from (
        select t.i, COALESCE(t1.o, 0) as o, COALESCE(t2.p, 0) as p, t.product_id
        from 
        (
          select SUM(CONVERT(number, UNSIGNED integer)) as i, product_id from ${inventory_table}  where type = 0 and product_id in ( ${product_ids} ) group by product_id
        ) 
        as t 
        left join 
        (select SUM(CONVERT(number, UNSIGNED integer)) as o, product_id from ${inventory_table}  where type = 1 and product_id in ( ${product_ids} ) group by product_id) 
        as t1 on t1.product_id = t.product_id 
        left join 
        (select SUM(CONVERT(number, UNSIGNED integer)) as p, product_id from ${inventory_table} where type = 2 and product_id in ( ${product_ids} ) group by product_id) 
        as t2 on t2.product_id = t.product_id 
        left join product as t3 on t3.uuid = t.product_id
      ) as m 
      left join ${product_table} as n on m.product_id = n.uuid
      group by m.product_id
      `;
      const [ product_inventory, rawList ] = await ctx.app.knex.raw(sql);
      let is_enough = '';
      for (const p of product_inventory) {
        const obj = products.find(f => {
          return f.product_id === p.product_id;
        });

        if ((p.number - obj.number) < 0) is_enough += `商品 ${p.name} 库存不足,\n`;
      }

      if (is_enough.length !== 0) {
        throw new Error(is_enough);
      }

    } catch (error) {
      throw error;
    }
  }

}

module.exports = OrderService;
